<template>
  <div class="vuefinder h-full" ref="root" tabindex="0">
    <div :class="app.theme.actualValue" class="h-full">
      <!-- <div
        :class="
          app.fullScreen
            ? 'vuefinder__main__fixed'
            : 'vuefinder__main__relative'
        "
        class="vuefinder__main__container"
        @mousedown="app.emitter.emit('vf-contextmenu-hide')"
        @touchstart="app.emitter.emit('vf-contextmenu-hide')"
      > -->
      <div
        class="vuefinder__main__container"
        @mousedown="app.emitter.emit('vf-contextmenu-hide')"
        @touchstart="app.emitter.emit('vf-contextmenu-hide')"
      >
        <ToolbarTemp :isManager="is_manager" />
        <div class="vuefinder__main__content">
          <Explorer :isManager="is_manager" />
        </div>
      </div>
      <Transition name="fade">
        <Component v-if="app.modal.visible" :is="app.modal.type" />
      </Transition>

      <ContextMenu />
    </div>
  </div>
</template>

<script setup>
import { inject, onMounted, provide, ref, watch } from 'vue'
import ServiceContainer from '../ServiceContainer.js'
import { useHotkeyActions } from '../composables/useHotkeyActions.js'
import ToolbarTemp from '../components/ToolbarTemp.vue'
import Breadcrumb from '../components/Breadcrumb.vue'
import Explorer from './Explorer.vue'
import ContextMenu from '../components/ContextMenu.vue'
import Statusbar from '../components/Statusbar.vue'
import TreeView from '../components/TreeView.vue'
import { menuItems as contextMenuItems } from '../utils/contextmenu.js'
import useObsUpload from '../utils/useObsUpload.js'
const emit = defineEmits(['select', 'update:path', 'error'])

const props = defineProps({
  id: {
    type: String,
    default: 'vf',
  },
  request: {
    type: [String, Object],
    required: true,
  },
  persist: {
    type: Boolean,
    default: false,
  },
  path: {
    type: String,
    default: '',
  },
  features: {
    type: [Array, Boolean],
    default: true,
  },
  debug: {
    type: Boolean,
    default: false,
  },
  theme: {
    type: String,
    default: 'system',
  },
  locale: {
    type: String,
    default: 'zhCN',
  },
  maxHeight: {
    type: String,
    default: '600px',
  },
  maxFileSize: {
    type: String,
    default: '10mb',
  },
  fullScreen: {
    type: Boolean,
    default: true,
  },
  showTreeView: {
    type: Boolean,
    default: false,
  },
  pinnedFolders: {
    type: Array,
    default: [],
  },
  showThumbnails: {
    type: Boolean,
    default: true,
  },
  selectButton: {
    type: Object,
    default(rawProps) {
      return {
        active: false,
        multiple: false,
        click: (items) => {
          // items is an array of selected items
          //
        },
        ...rawProps,
      }
    },
  },
  onError: {
    type: Function,
    default: null,
  },
  loadingIndicator: {
    type: String,
    default: 'circular',
  },
  contextMenuItems: {
    type: Array,
    default: () => contextMenuItems,
  },
  requestParams: {
    type: Object,
    default: () => ({}),
  },
})

const is_manager = ref(false)
// the object is passed to all components as props
const app = ServiceContainer(props, inject('VueFinderOptions'))
provide('ServiceContainer', app)
const { setStore } = app.storage

//  Define root element
const root = ref(null)
app.root = root

// Define dragSelect object
const ds = app.dragSelect

useHotkeyActions(app)

const updateItems = (data) => {
  Object.assign(app.fs.data, data)
  is_manager.value = data.is_manager
  ds.clearSelection()
  ds.refreshSelection()
}

/** @type {AbortController} */
let controller
app.emitter.on('vf-fetch-abort', () => {
  controller.abort()
  app.fs.loading = false
})

// 上传文件
app.emitter.on(
  'vf-fetch-upload',
  async ({
    params,
    body = null,
    onSuccess = null,
    onError = null,
    noCloseModal = false,
  }) => {
    const { progress, error, isUploading, uploadFile } = useObsUpload(app)
    const fileUrl = await uploadFile(params.file)
    app.requester
      .send({
        method: 'post',
        params: {
          fetchType: 'uploadFile',
        },
        body: {
          ...body,
          project_id: app.requestParams.project_id,
          enterprise_id: app.requestParams.enterprise_id,
          url: fileUrl,
        },
      })
      .then(({ code, data, msg }) => {
        if (code !== 200) {
          if (onError) {
            onError({ message: msg })
          }
          return
        }
        if (onSuccess) {
          onSuccess(data)
        }
      })
      .catch((e) => {
        console.error(e)
        if (onError) {
          onError(e)
        }
      })
  }
)

// Fetch data
app.emitter.on(
  'vf-fetch',
  ({
    params,
    body = null,
    onSuccess = null,
    onError = null,
    noCloseModal = false,
  }) => {
    if (['index', 'search'].includes(params.q)) {
      if (controller) {
        controller.abort()
      }
      app.fs.loading = true
    }
    controller = new AbortController()
    const signal = controller.signal
    app.requester
      .send({
        url: '/getmicrodiskbyuser',
        method: params.m || 'get',
        params,
        body,
        abortSignal: signal,
      })
      .then(({ code, data, msg }) => {
        if (code !== 200) {
          if (onError) {
            onError({ message: msg })
          }
          return
        }
        if (data) {
          app.fs.adapter = data.adapter
          let fullPathList = [...app.fs.fullPathList]
          const index = fullPathList.findIndex(
            (item) => item.path === data.dirname
          )
          const nowData = {
            ...data,
            adapter: data.adapter,
            path: data.dirname,
            dir_id: data.dir_id,
          }
          if (index >= 0) {
            fullPathList[index] = nowData
          } else {
            fullPathList.push(nowData)
          }
          app.fs.fullPathList = fullPathList.filter(
            (n) => data.dirname.indexOf(n.path) >= 0
          )
          if (app.persist) {
            app.fs.path = data.dirname
            setStore('path', app.fs.path)
          }
          updateItems(data)
        }
        if (!noCloseModal) {
          app.modal.close()
        }
        if (onSuccess) {
          onSuccess(data)
        }
      })
      .catch((e) => {
        emit('error', e)
        // if (onError) {
        //   console.log(3333);
        //   onError(e)
        // }
      })
      .finally(() => {
        if (['index', 'search'].includes(params.q)) {
          app.fs.loading = false
        }
      })
  }
)

// 搜索文件
app.emitter.on(
  'vf-fetch-search',
  ({
    params,
    body = null,
    onSuccess = null,
    onError = null,
    noCloseModal = false,
  }) => {
    app.requester
      .send({
        url: '/searchmicrodiskbydir',
        method: params.m || 'get',
        params,
        body,
      })
      .then(({ code, data, msg }) => {
        if (code !== 200) {
          if (onError) {
            onError({ message: msg })
          }
          return
        }
        if (data) {
          app.fs.adapter = data.adapter
          const fullPathList = [
            ...app.fs.fullPathList,
            ...data.files.map((n) => ({
              ...n,
              adapter: data.adapter,
              dir_id: n.id,
            })),
          ]
          app.fs.fullPathList = fullPathList
          if (app.persist) {
            app.fs.path = data.dirname
            setStore('path', app.fs.path)
          }
          updateItems(data)
        }
        if (onSuccess) {
          onSuccess(data)
        }
      })
      .catch((e) => {
        console.error(e)
        if (onError) {
          onError(e)
        }
      })
      .finally(() => {
        if (['index', 'search'].includes(params.q)) {
          app.fs.loading = false
        }
      })
  }
)

/**
 * fetchPath fetches the items of the given path
 * if no path is given, the backend should return the root of the current adapter
 * @param path {string | undefined} example: 'media://public'
 */
function fetchPath(path) {
  let pathExists = {}

  if (path && path.includes('://')) {
    pathExists = {
      adapter: path.split('://')[0],
      path: path,
    }
  }

  app.emitter.emit('vf-fetch', {
    params: { q: 'index', adapter: app.fs.adapter, ...pathExists },
    onError:
      props.onError ??
      ((e) => {
        if (e.message) {
          app.emitter.emit('vf-toast-push', { label: e.message, type: 'error' })
        }
      }),
  })
}

// fetch initial data
onMounted(() => {
  // app.fs.adapter can be null at first, until we get the adapter list it will be the first one from response
  // later we can set default adapter from a prop value

  // if there is a path coming from the prop, we should use it.
  fetchPath(app.fs.path)

  // We re-fetch the data if the path prop is updated
  watch(
    () => props.path,
    (path) => {
      fetchPath(path)
    }
  )

  // Emit select event
  ds.onSelect((items) => {
    emit('select', items)
  })

  // Emit update:path event
  watch(
    () => app.fs.data.dirname,
    (path) => {
      emit('update:path', path)
    }
  )
})

// 切换排列方式
function toggleTreeView(modal) {
  app.view = !!modal ? modal : app.view === 'list' ? 'grid' : 'list'
  ds.refreshSelection()
  setStore('viewport', app.view)
}

// 搜索文件
const searchQuery = (newQuery) => {
  app.emitter.emit('vf-toast-clear')
  app.emitter.emit('vf-search-query', { newQuery })
  // app.emitter.emit('vf-fetch', {params: {dir: app.fs.data.dirname, dir_id: app.fs.data.dir_id, searchkey: newQuery}});
}

defineExpose({
  toggleTreeView,
  searchQuery,
})
</script>
